﻿using System.Diagnostics;

namespace LinearRegression
{
    internal class Program
    {
        /// <summary>
        /// 用最小二乘法对GDP进行拟合
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            //存放年份的List
            List<double> theYear = new List<double>();
            for (int iYear = 1978; iYear<=2021; iYear++)
            {
                theYear.Add(iYear);
            }
            //转为数组
            double[] Year = theYear.ToArray();
            //1978-2021 GDP原始数据数组
            double[] gdp =
            {
                149540752829, 178280594413, 191149211575, 195866382432, 205089699858,
                230686747153, 259946510957, 309488028132, 300758100107, 272972974764,
                312353631207, 347768051311, 360857912565, 383373318083, 426915712715,
                444731282435, 564324670008, 734547898224, 863746717507, 961603952954,
                1029043097558, 1093997267277, 1211346869600, 1339395718862, 1470550015077,
                1660287965663, 1955347004965, 2285965892364, 2752131773358, 3550342737009,
                4594307032667, 5101703073088, 6087163874510, 7551500124197, 8532229986993,
                9570406235659, 10475682920597, 11061553079871, 11233276536744, 12310409370894,
                13894817549380, 14279937500608, 14687673892882,17734062645371
            };
            //输入年份
            Console.WriteLine("请输入要预测的年份：");
            int aimYear = Convert.ToInt32(Console.ReadLine());
            //输出预测            
            Console.WriteLine($"{aimYear}年份的预测值为{Methods.LRMethods(aimYear, Year, gdp)}元人民币");
            //输出预测值与实际值的差
            Console.WriteLine($"{aimYear}年份的预测值与实际值的差为" +
                $"{Methods.Tolerance(aimYear, gdp, Methods.LRMethods(aimYear, Year, gdp))}元");
            //输出拟合优度
            Console.WriteLine($"拟合优度为：" +
                $"{Methods.R_Squared(aimYear, Year, gdp, Methods.LRMethods(aimYear, Year, gdp))}");
        }
    }
    /// <summary>
    /// 方法类
    /// </summary>
    public class Methods
    {
        //方法1：计算线性回归参数
        public static double LRMethods(double aimYear, double[] Year, double[] gdp)
        {
            //计算年份和GDP的平均值
            double averYear = 0;
            double averGDP = 0;
            foreach (double element in Year)
            {
                averYear+=element;
            }
            foreach (double element in gdp)
            {
                averGDP+=element;
            }
            averYear/=Year.Length;
            averGDP/=gdp.Length;
            //计算b和a
            double upA = 0, downB = 0;
            for (int i = 0; i < Year.Length; i++)
            {
                upA+=(Year[i]-averYear)*(gdp[i]-averGDP);
                downB+=(Year[i]-averYear)*(Year[i]-averYear);
            }
            double b = upA/downB;
            double a = averGDP-b*averYear;
            return a+b*aimYear;
        }
        //方法2：计算预测值和实际值的差
        public static double Tolerance(int aimYear, double[] gdp, double predict)
        {
            //2022年及以后的GDP未知
            if (aimYear >2021)
            {
                Console.WriteLine("结果未知");
                return 0;
            }
            else
            {
                double Year = aimYear;
                double GDP = gdp[aimYear-1978];
                return predict-GDP;
            }
        }
        //方法3:计算拟合优度判断拟合程度
        public static double R_Squared(int aimYear, double[] Year, double[] gdp, double predict)
        {

            //拟合优度R2
            double R2 = 0;
            //总平方和SST
            double SST = 0;
            //残差平方和SSR
            double SSR = 0;
            double averGDP = 0;
            //求SST
            foreach (double element in gdp)
            {
                averGDP+=element;
            }
            averGDP/=gdp.Length;
            for (int i = 0; i <Year.Length; i++)
            {
                SST+=(gdp[i]-averGDP)*(gdp[i]-averGDP);
            }
            //求所有年份GDP以及SSR
            for (int i = 0; i<Year.Length; i++)
            {
                SSR+=(Methods.LRMethods(i+1978, Year, gdp)-gdp[i])*(Methods.LRMethods(i+1978, Year, gdp)-gdp[i]);
            }
            //求R2
            R2=1-SSR/SST;
            return R2;

        }


    }
}


